package Cinema.CinemaEntities;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import Utils.XmlParseHelper;
import Cinema.DataLayer.IXmlParsable;
import Cinema.DataLayer.XmlDefines;
import Exceptions.WrongXMLElement;


/**
 * An abstract class for 'BigSite' and 'SmallSite'.
 * Represents a common behavior of 'BigSite' and 'SmallSite'.
 * @author The Fuchtzeinsoft Team.
 *
 */
public  abstract class Site implements IXmlParsable,IMapItem {

	/**
	 * construct a new Site instance.
	 * @param siteName - the name of the new site.
	 * @param siteLocation - the location of the new site.
	 */
	protected Site(String siteName, Location siteLocation ,String city){
		this.name = siteName;
		this.location = siteLocation;
		this.city=city;
	}

	/**
	 * Construct a new Site instance according to an xmlElement.
	 * @param xmlElement - the XML element that describe the new Site.
	 * @throws WrongXMLElement
	 */
	protected Site(Element xmlElement) throws WrongXMLElement{

	}

	protected String name;
	@Override
	public String getName() {
		return name;
	}

	protected Location location;
	@Override
	public Location getLocation() {
		return location;
	}

	protected String city;
	@Override
	public String getCity() {
		return city;
	}

	/**
	 * @return a collectio of the theaters in the site.
	 */
	public abstract Set<Theater> getTheaters();

	//for tests
	public boolean checkEquals(Object obj) {
		if (!(obj instanceof Site)){
			return false;
		}
		Site site = (Site)obj;
		if (!city.equals(site.city)){
			return false;
		}
		if (location.getX() != site.location.getX()){
			return false;
		}
		if (location.getY() != site.location.getY()){
			return false;
		}
		if (!name.equals(site.name)){
			return false;
		}
		if (this.getTheaters().size() != this.getTheaters().size()) {
			return false;
		}
		for (Theater t : getTheaters()) {
			boolean b = false;
			for (Theater tOther : site.getTheaters()) {
				if (t.checkEquals(tOther)){
					b = true;
				}
			}
			if (b==false){
				return false;
			}
		}
		return true;
	}

	/**
	 * a request to get all the presenting movies that are showing in the site.
	 * @return all the movies that present in the current site.
	 */
	public Set<Movie> getPresentingMovies() {
		HashSet<Movie> movies = new HashSet<Movie>();
		for (Theater theater : this.getTheaters()) {
			for (IShow show : theater.getShows()) {
				movies.add(show.getMovie());
			}
		}
		return movies;
	}

	/**
	 * return the distance from another site.
	 * @param site - a site to measure the distance from.
	 * @return the distance from the site.
	 */
	public double Distance(Site site){
		return this.location.distance(site.location);
	}

	@Override
	public void initFromXml(Element xmlElement) throws WrongXMLElement {

	}

	@Override
	public void initFromXml(boolean isRestoring, Element xmlElement) throws WrongXMLElement {

		//verifying that write xml element given
		if (!xmlElement.getTagName().equals(XmlDefines.SITE)){
			throw new WrongXMLElement();
		}

		//init sites name
		name = XmlParseHelper.getFirstChildByName(xmlElement, XmlDefines.NAME).getTextContent();

		//init list of theaters
		ArrayList<Element> theaterElements;
		if(isRestoring){
			Element theaterListElement = XmlParseHelper.getFirstChildByName(xmlElement, XmlDefines.THEATER_LIST);
			theaterElements = XmlParseHelper.getChildrenByName(theaterListElement, XmlDefines.THEATER);
		}
		else{
			theaterElements = XmlParseHelper.getChildrenByName(xmlElement, XmlDefines.THEATER);
		}
		Set<Theater> theatres = getTheaters();
		for (Element element : theaterElements) {
			theatres.add(new Theater(isRestoring, element));
		}

		if (isRestoring){
			city = XmlParseHelper.getFirstChildByName(xmlElement, XmlDefines.CITY).getTextContent();
			Element locationElement = XmlParseHelper.getFirstChildByName(xmlElement, XmlDefines.LOCATION);
			String xString = XmlParseHelper.getFirstChildByName(locationElement, XmlDefines.X_LOCATION).getTextContent();
			String yString = XmlParseHelper.getFirstChildByName(locationElement, XmlDefines.Y_LOCATION).getTextContent();
			location = new Location(Integer.parseInt(xString), Integer.parseInt(yString));
		}
		else{
			//init location and city
			if (theatres.iterator().hasNext()){
				location = theatres.iterator().next().getLocation();
				city = theatres.iterator().next().getCity();
			}
			else{
				location = UNDEFINED_LOCATION;
				city = UNDEFINED_CITY_STRING;
			}
		}

	}

	@Override
	public Element getXml(Document document) {

		//create representing element
		Element siteElement = document.createElement(XmlDefines.SITE);

		//create field for name
		Element nameElement = document.createElement(XmlDefines.NAME);
		siteElement.appendChild(nameElement);
		nameElement.setTextContent(name);

		//create field for city
		Element cityElement = document.createElement(XmlDefines.CITY);
		siteElement.appendChild(cityElement);
		cityElement.setTextContent(city);

		//create field for location
		Element locationElement = document.createElement(XmlDefines.LOCATION);
		siteElement.appendChild(locationElement);
		Element xLocationElement = document.createElement(XmlDefines.X_LOCATION);
		xLocationElement.setTextContent(new Integer(location.getX()).toString());
		locationElement.appendChild(xLocationElement);
		Element yLocationElement = document.createElement(XmlDefines.Y_LOCATION);
		yLocationElement.setTextContent(new Integer(location.getY()).toString());
		locationElement.appendChild(yLocationElement);


		//crating list of theater xml elements
		Element theaterListElement = document.createElement(XmlDefines.THEATER_LIST);
		siteElement.appendChild(theaterListElement);
		Iterator<Theater> theaterIterator = getTheaters().iterator();
		while(theaterIterator.hasNext()){
			Theater currentTheater = theaterIterator.next();
			theaterListElement.appendChild(currentTheater.getXml(document));
		}

		return siteElement;
	}

	//--------------------------   final static data  ----------------------------------------
	private final static String UNDEFINED_CITY_STRING = "Undefined City";
	private final static Location UNDEFINED_LOCATION = new Location(0, 0);

}
